<?php

namespace Fize\Third\Dify;

use Fize\Codec\Json;
use Fize\Exception\ThirdException;
use Fize\Http\ClientSimple;
use Psr\Http\Message\ResponseInterface;

abstract class ApiAbstract
{

    /**
     * 通用域名
     */
    const HOST = 'https://api.dify.ai';

    /**
     * @var string 域名
     */
    protected $host;

    /**
     * @var string API密钥
     */
    protected $apiKey;

    /**
     * @var string URL路径前缀
     */
    protected $pathPrefix = '/v1';

    /**
     * @var ClientSimple HTTP客户端
     */
    protected $httpClient;

    /**
     * @param string $apiKey API密钥
     */
    public function __construct(string $apiKey, string $host = null)
    {
        if (empty($host)) {
            $host = self::HOST;
        }
        $this->host = $host;
        $this->apiKey = $apiKey;
        $this->httpClient = new ClientSimple($this->host);
    }

    /**
     * 获取完整URL
     * @param string      $path       路径
     * @param string|null $pathPrefix 路径前缀
     * @return string
     */
    protected function getUrl(string $path, string $pathPrefix = null): string
    {
        $pathPrefix = is_null($pathPrefix) ? $this->pathPrefix : $pathPrefix;
        return self::HOST . $pathPrefix . $path;
    }

    /**
     * 获取访问路径
     * @param string      $path       路径
     * @param string|null $pathPrefix 路径前缀
     * @return string
     */
    protected function getPath(string $path, string $pathPrefix = null): string
    {
        $pathPrefix = is_null($pathPrefix) ? $this->pathPrefix : $pathPrefix;
        return $pathPrefix . $path;
    }

    protected function httpPost(string $path, $params, bool $paramsJsonEncode = true, bool $contentJsonDecode = true, bool $checkContentType = false, string $pathPrefix = null)
    {
        $headers = [
            'Authorization' => 'Bearer ' . $this->apiKey
        ];
        if ($paramsJsonEncode) {
            $headers['Content-Type'] = 'application/json';
            $params = Json::encode($params, JSON_UNESCAPED_UNICODE);
        }
        $uri = $this->getPath($path, $pathPrefix);
        $response = $this->httpClient->post($uri, $params, $headers);
        return $this->handleResponse($response, $contentJsonDecode, $checkContentType);
    }

    protected function httpGet(string $path, bool $contentJsonDecode = true, bool $checkContentType = false, string $pathPrefix = null)
    {
        $uri = $this->getPath($path, $pathPrefix);
        $headers = [
            'Authorization' => 'Bearer ' . $this->apiKey,
            'Content-Type' => 'application/json'
        ];
        $response = $this->httpClient->get($uri, $headers);
        return $this->handleResponse($response, $contentJsonDecode, $checkContentType);
    }

    protected function httpDelete(string $path, string $pathPrefix = null)
    {
        $uri = $this->getPath($path, $pathPrefix);
        $headers = [
            'Authorization' => 'Bearer ' . $this->apiKey,
            'Content-Type' => 'application/json'
        ];
        $response = $this->httpClient->delete($uri, $headers);
        if ($response->getStatusCode() == 404) {  // 【不存在】视为【已删除】。
            return true;
        }
        return $this->handleResponse($response, false);
    }

    /**
     * 统一处理响应
     * @param ResponseInterface $response         响应对象
     * @param bool              $jsonDecode       是否对结果进行JSON解码
     * @param bool              $checkContentType 是否对内容进行类型识别
     * @return array|string
     */
    protected function handleResponse(ResponseInterface $response, bool $jsonDecode = true, bool $checkContentType = false)
    {
        if ($response->getStatusCode() != 200) {
            $body = $response->getBody();
            if ($body) {
                throw new ThirdException('Dify', $body);
            }
            throw new ThirdException('Dify', $response->getReasonPhrase(), $response->getStatusCode());
        }
        $content = $response->getBody()->getContents();
        if ($checkContentType) {
            $ContentType = $response->getHeaderLine('Content-Type');
            if ($ContentType == 'text/plain') {
                if ($jsonDecode) {
                    $json = Json::decode($content);
                    if (isset($json['errcode']) && $json['errcode']) {
                        throw new ThirdException('Dify', $json['errmsg'], $json['errcode']);
                    }
                    return [  // 返回JSON
                        'type'  => 'json',
                        'value' => $json
                    ];
                } else {
                    return [  // 返回HTML
                        'type'  => 'html',
                        'value' => $content
                    ];
                }
            }
            return [  // 返回二进制流
                'type'  => 'binary',
                'value' => $content
            ];
        }
        if ($jsonDecode) {
            $json = Json::decode($content);
            return $json;
        } else {
            return $content;
        }
    }
}